#include "pipe_elements.h"
#include <map>
#include <string>
#include <iostream>
#include <stack>

using namespace std;
extern stack <int> rsremovelist;
extern int debug;
ROB::ROB()
{
    for(int i=0;i<10;i++)
    {
        ROBlist[i].entry=i+1;
        ROBlist[i].busy=0;
        ROBlist[i].address=0;
        ROBlist[i].state=0;
        ROBlist[i].value=0;
        ROBlist[i].destination=0;
    }
}
int ROB::freeid()
{
    for(int i=0;i<10;i++)
    {
        if(!ROBlist[i].busy)
            return i;
    }
    return -1;
}
void ROB::addat(int id, iQelement iqe,int cycle,registerFile &rRF)
{
    ROBlist[id].busy=1;
    ROBlist[id].state=0;
    ROBlist[id].destination=iqe.instruction.destination;
    ROBlist[id].value=-1;
    ROBlist[id].instruction=iqe.instruction;
    ROBlist[id].issuecycle=cycle;
    if(!iqe.instruction.opcode.compare("NOP")||!iqe.instruction.opcode.compare("BREAK"))
    {
        ROBlist[id].updatecycle=cycle;
        ROBlist[id].state=COMMIT;
    }

    if(ROBlist[id].instruction.isjump)
    {
        ROBlist[id].busy=1;
        ROBlist[id].updatecycle=cycle;

        ROBlist[id].state=0;
    }
    if(ROBlist[id].destination!=-1)
    {
        //cout<<"\nTHIS is busy :"<<ROBlist[id].destination<<endl;
        rRF.setbusy(ROBlist[id].destination);
        rRF.setrobid(ROBlist[id].destination,id);
    }
}
int ROB::commitable(int cycle)//rewrite
{
    if(!ROBlist[0].busy)
    {
        return 1;
    }
    return 0;
}

int ROB::isready(int i)
{
    return ROBlist[i].state;
}

int ROB::getvalue(int a)
{
    return ROBlist[a].value;
}
void ROB::fprint()
{
    cout<<"ROB:\n";
    for(int i=0;i<10;i++)
    {
        if(ROBlist[i].busy)
        {
            cout<<"[";
            ROBlist[i].instruction.fprint();
            cout<<"]";
            if(debug)
                cout<<"[id:"<<i<<" Busy:"<<ROBlist[i].busy<<" D:"<<ROBlist[i].destination<<" v:"<<ROBlist[i].value<<" s:"<<ROBlist[i].state<<"]";
            cout<<"\n";
        }
    }
}
extern int lastaddress;
void ROB::update(CDBmember data,int cycle,CDB &rCDB)
{
    if(ROBlist[data.robid].issuecycle==cycle)
        return;
    if(!data.optype.compare("SW"))
    {
        ROBlist[data.robid].destination=data.result;
        ROBlist[data.robid].value=data.value;
        ROBlist[data.robid].state=WRITERESULT;
        ROBlist[data.robid].updatecycle=cycle;
        rsremovelist.push(data.rsnumber);
    }
    else if(!data.optype.compare("LW"))
    {
        if(data.loadcounter==0)
        {
            //cout<<"\nINDEED a job well done \n";
        ROBlist[data.robid].value=data.result;
        ROBlist[data.robid].state=WRITERESULT;
        ROBlist[data.robid].updatecycle=cycle;
        rsremovelist.push(data.rsnumber);
        }
        else
        {
            if((data.value<700)||(data.value>lastaddress))
                    cout<<"Segmentation Fault , out of range Memory access\n";

            data.result=mMemory[data.value].value;

            data.loadcounter=0;
            data.cycle=cycle;
            cout<<"\n\nPushed it back \n";
            rCDB.add(cycle,data.result,data.value,data.robid,data.optype,0,data.rsnumber);

        }
    }
    else
    {
        ROBlist[data.robid].value=data.result;
        ROBlist[data.robid].state=WRITERESULT;
        ROBlist[data.robid].updatecycle=cycle;
        rsremovelist.push(data.rsnumber);
    }

}
int ROB::head(int i)
{
    for(int k=0;k<10;k++)
    {
        if(ROBlist[k].busy)
        {
        if(ROBlist[k].issuecycle<ROBlist[i].issuecycle)
            return 0;
    
        }
    }
    return 1;
}
extern int kill;
int ROB::commit(registerFile & rRF,int cycle)
{
    for(int i=0;i<10;i++)
    {
        if(ROBlist[i].state==WRITERESULT && ROBlist[i].updatecycle<cycle && head(i) )
        {

            if(debug)
                cout<<"Commiting Instruction ";ROBlist[i].instruction.fprint();cout<<endl;
            if(!ROBlist[i].instruction.opcode.compare("SW"))
            {
            if(ROBlist[i].destination<700||ROBlist[i].destination>lastaddress)
            {
                cout<<"Error out of range memory access\n";
                kill=1;
                return 0;
            }
                mMemory[ROBlist[i].destination].value=rRF.getvalue(ROBlist[i].value);
                ROBlist[i].clear();
                return 0;
            }
            else if(ROBlist[i].instruction.isjump)
            {
                ROBlist[i].busy=0;
            }
            else
            {
                

                rRF.write(ROBlist[i].destination,ROBlist[i].value);
                ROBlist[i].clear();
                return 1;
            }

        }
        if(ROBlist[i].state==COMMIT && ROBlist[i].updatecycle<cycle && head(i) )
        {

            if(debug)
                cout<<"Commiting Instruction ";ROBlist[i].instruction.fprint();cout<<endl;

            ROBlist[i].clear();
            return 1;
        }
    }
    return 1;
}
void ROB::flush(int ic)
{
    for(int i=0;i<10;i++)
    {
        if(ROBlist[i].issuecycle>ic)
        {
            ROBlist[i].clear();
        }
    }
}